home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / smaltalk / manchest.lha / MANCHESTER / manchester / 2.2 / Calculator.st < prev    next >
Text File  |  1993-07-24  |  21KB  |  811 lines

  1. "    NAME        Calculator
  2.     AUTHOR        TPH@cs.man.ac.uk
  3.     FUNCTION faster & better & keyboard drivable 
  4.     ST-VERSIONS    2.2
  5.     PREREQUISITES     
  6.     CONFLICTS    
  7.     DISTRIBUTION      world
  8.     VERSION        1.1
  9.     DATE    22 Jan 1989
  10. SUMMARY    Calculator
  11.     is a new version of the credit-card calculator.  It is
  12.         significantly faster than the previous version, as well as
  13.         having much less code!  Also, a couple of new features: a
  14.         `raise-to-power' button, and bindings to keyboard characters
  15.         (so that you can type at it!).  Tested with VI2.2 and VI2.3.
  16.         Could probably be made to work with earlier versions. TPH,
  17.     11/2/89. (2.2)  
  18. "!
  19. MouseMenuController subclass: #CalculatorController
  20.     instanceVariableNames: ''
  21.     classVariableNames: 'CalculatorYellowButtonMenu CalculatorYellowButtonMessages '
  22.     poolDictionaries: ''
  23.     category: 'Interface-Calculator'!
  24.  
  25.  
  26. !CalculatorController methodsFor: 'initialize-release'!
  27.  
  28. initialize
  29.     super initialize.
  30.     self initializeYellowButtonMenu! !
  31.  
  32. !CalculatorController methodsFor: 'control defaults'!
  33.  
  34. isControlActive
  35.     ^super isControlActive & sensor blueButtonPressed not! !
  36.  
  37. !CalculatorController methodsFor: 'menu messages'!
  38.  
  39. changeDigitLength
  40.     "Change the number of digits displayed."
  41.  
  42.     | answerString |
  43.     answerString _ FillInTheBlank
  44.                 request: 'Number of digits to be displayed?'
  45.                 initialAnswer: model noOfDigits printString.
  46.     answerString isEmpty ifFalse: [
  47.         model noOfDigits: (Number readFrom: (ReadStream on: answerString))]!
  48.  
  49. setLeftJustify
  50.     "Display as left-justified."
  51.  
  52.     model leftJustify ifFalse: [model leftJustify: true]!
  53.  
  54. setRightJustify
  55.     "Display as right-justified."
  56.  
  57.     model leftJustify ifTrue: [model leftJustify: false]! !
  58.  
  59. !CalculatorController methodsFor: 'private'!
  60.  
  61. initializeYellowButtonMenu
  62.     "Initialize the middle button menu."
  63.  
  64.     self
  65.         yellowButtonMenu: CalculatorYellowButtonMenu
  66.         yellowButtonMessages: CalculatorYellowButtonMessages! !
  67. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  68.  
  69. CalculatorController class
  70.     instanceVariableNames: ''!
  71.  
  72.  
  73. !CalculatorController class methodsFor: 'class initialization'!
  74.  
  75. initialize
  76.     "Specify the Yellow button menu and messages."
  77.     "CalculatorController initialize."
  78.  
  79.     CalculatorYellowButtonMenu _ PopUpMenu
  80.             labels: ' Digit Length \ Left Justify \ Right Justify ' withCRs
  81.             lines: #(1).
  82.     CalculatorYellowButtonMessages _ #(changeDigitLength setLeftJustify setRightJustify).! !
  83.  
  84. CalculatorController initialize!
  85.  
  86.  
  87. Model subclass: #Calculator
  88.     instanceVariableNames: 'displayValue accumulatorValue currentOperation doneOperation noOfDigits errorFlag pointPlaces trailingZeros leftJustify '
  89.     classVariableNames: 'DefaultNoOfDigits '
  90.     poolDictionaries: ''
  91.     category: 'Interface-Calculator'!
  92.  
  93.  
  94. !Calculator methodsFor: 'initialize-release'!
  95.  
  96. initialize
  97.     "Initialize the receiver."
  98.  
  99.     displayValue _ 0.
  100.     accumulatorValue _ 0.
  101.     currentOperation _ nil.
  102.     doneOperation _ true.
  103.     errorFlag _ false.
  104.     pointPlaces _ 0.
  105.     trailingZeros _ 0.
  106.     leftJustify _ true.
  107.     noOfDigits _ DefaultNoOfDigits! !
  108.  
  109. !Calculator methodsFor: 'accessing'!
  110.  
  111. displayValue
  112.     "Answers with the current display value."
  113.  
  114.     ^displayValue!
  115.  
  116. errorFlag
  117.     "Answer the error flag value."
  118.  
  119.     ^errorFlag!
  120.  
  121. leftJustify
  122.     "Answer the current value of the left justify flag."
  123.  
  124.     ^leftJustify!
  125.  
  126. leftJustify: aBoolean
  127.     "Set the current value of the left justify flag."
  128.  
  129.     leftJustify _ aBoolean.
  130.     self changed!
  131.  
  132. noOfDigits
  133.     "Answer the number of digits represented."
  134.  
  135.     ^noOfDigits!
  136.  
  137. noOfDigits: aNumber
  138.     "Sets the number of digits represented to aNumber."
  139.  
  140.     noOfDigits _ aNumber.
  141.     self changed!
  142.  
  143. trailingZeros
  144.     "Answer the number of trailing zeros."
  145.  
  146.     ^trailingZeros! !
  147.  
  148. !Calculator methodsFor: 'operation keys'!
  149.  
  150. add
  151.     "Make the current operation addition."
  152.  
  153.     self doOperation.
  154.     currentOperation _ #addition.!
  155.  
  156. changeSign
  157.     "Change the sign of the value in the display register."
  158.  
  159.     self makeDisplay: displayValue negated!
  160.  
  161. clear
  162.     "Clear the error flag.  Clear the display and accumulator registers."
  163.  
  164.     errorFlag _ false.
  165.     pointPlaces _ 0.
  166.     trailingZeros _ 0.
  167.     accumulatorValue _ 0.
  168.     currentOperation _ nil.
  169.     self makeDisplay: 0!
  170.  
  171. clearEntry
  172.     "Zero the display register."
  173.  
  174.     pointPlaces _ 0.
  175.     trailingZeros _ 0.
  176.     self makeDisplay: 0!
  177.  
  178. divide
  179.     "Make the current operation division."
  180.  
  181.     self doOperation.
  182.     currentOperation _ #division!
  183.  
  184. equals
  185.     "Perform the current operation, putting the answer in
  186.      the accumulator. Display the answer."
  187.  
  188.     self performOperation: currentOperation.
  189.     self makeDisplay: accumulatorValue.
  190.     doneOperation _ true.
  191.     trailingZeros _ 0.
  192.     currentOperation _ nil!
  193.  
  194. multiply
  195.     "Make the current operation multiplication."
  196.  
  197.     self doOperation.
  198.     currentOperation _ #multiplication!
  199.  
  200. point
  201.     "Insert a decimal point. Sets the number of decimal places to 1."
  202.  
  203.     pointPlaces = 0 ifTrue: [pointPlaces _ 1]!
  204.  
  205. raiseTo
  206.     "Make the current operation raise-to-power."
  207.  
  208.     self doOperation.
  209.     currentOperation _ #raiseTo!
  210.  
  211. subtract
  212.     "Make the current operation subtraction."
  213.  
  214.     self doOperation.
  215.     currentOperation _ #subtraction.! !
  216.  
  217. !Calculator methodsFor: 'digit keys'!
  218.  
  219. add0
  220.     "Add 0 to the display value."
  221.  
  222.     pointPlaces > 0 ifTrue: [trailingZeros _ trailingZeros + 1].
  223.     self addToDisplay: 0.!
  224.  
  225. add1
  226.     "Add 1 to the display value."
  227.  
  228.     trailingZeros _ 0.
  229.     self addToDisplay: 1.!
  230.  
  231. add2
  232.     "Add 2 to the display value."
  233.  
  234.     trailingZeros _ 0.
  235.     self addToDisplay: 2.!
  236.  
  237. add3
  238.     "Add 3 to the display value."
  239.  
  240.     trailingZeros _ 0.
  241.     self addToDisplay: 3.!
  242.  
  243. add4
  244.     "Add 4 to the display value."
  245.  
  246.     trailingZeros _ 0.
  247.     self addToDisplay: 4.!
  248.  
  249. add5
  250.     "Add 5 to the display value."
  251.  
  252.     trailingZeros _ 0.
  253.     self addToDisplay: 5.!
  254.  
  255. add6
  256.     "Add 6 to the display value."
  257.  
  258.     trailingZeros _ 0.
  259.     self addToDisplay: 6.!
  260.  
  261. add7
  262.     "Add 7 to the display value."
  263.  
  264.     trailingZeros _ 0.
  265.     self addToDisplay: 7.!
  266.  
  267. add8
  268.     "Add 8 to the display value."
  269.  
  270.     trailingZeros _ 0.
  271.     self addToDisplay: 8.!
  272.  
  273. add9
  274.     "Add 9 to the display value."
  275.  
  276.     trailingZeros _ 0.
  277.     self addToDisplay: 9.! !
  278.  
  279. !Calculator methodsFor: 'private'!
  280.  
  281. addToDisplay: aNumber 
  282.     "Adds a number to the display value. The model has    
  283.      changed."
  284.  
  285.     | temp |
  286.     doneOperation ifTrue: [
  287.         displayValue _ 0.
  288.         doneOperation _ false].
  289.     displayValue < 0
  290.         ifTrue: [temp _ aNumber negated]
  291.         ifFalse: [temp _ aNumber].
  292.     pointPlaces ~= 0
  293.         ifTrue: [
  294.             self makeDisplay: displayValue +
  295.                 (temp / (10 raisedToInteger: pointPlaces)).
  296.             pointPlaces _ pointPlaces + 1]
  297.         ifFalse: [self makeDisplay: displayValue * 10 + temp]!
  298.  
  299. doOperation
  300.     "Do the current operation (if any).  Update the display
  301.      and accumulator."
  302.  
  303.     currentOperation notNil ifTrue: [
  304.         self performOperation: currentOperation.
  305.         self makeDisplay: accumulatorValue].
  306.     trailingZeros _ 0.
  307.     pointPlaces _ 0.
  308.     doneOperation _ true.
  309.     accumulatorValue _ displayValue.!
  310.  
  311. makeDisplay: aNumber 
  312.     "Makes aNumber the display value. The model has changed."
  313.  
  314.     aNumber >= (10 raisedToInteger: noOfDigits)
  315.         ifTrue: [errorFlag _ true]
  316.         ifFalse: [displayValue _ aNumber].
  317.     self changed!
  318.  
  319. performOperation: aSymbol 
  320.     "Perform the operation given by aSymbol."
  321.  
  322.     aSymbol = #addition ifTrue: [
  323.         accumulatorValue _ accumulatorValue + displayValue].
  324.     aSymbol = #subtraction ifTrue: [
  325.         accumulatorValue _ accumulatorValue - displayValue].
  326.     aSymbol = #multiplication ifTrue: [
  327.         accumulatorValue _ accumulatorValue * displayValue].
  328.     aSymbol = #division ifTrue: [
  329.         displayValue = 0
  330.             ifTrue: [errorFlag _ true.]
  331.             ifFalse: [accumulatorValue _ accumulatorValue / displayValue]].
  332.     aSymbol = #raiseTo ifTrue: [
  333.         accumulatorValue _ accumulatorValue raisedTo: displayValue].
  334.     pointPlaces _ 0! !
  335. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  336.  
  337. Calculator class
  338.     instanceVariableNames: ''!
  339.  
  340.  
  341. !Calculator class methodsFor: 'instance creation'!
  342.  
  343. new
  344.     "Create a new initialized instance of the receiver."
  345.  
  346.     ^super new initialize!
  347.  
  348. new: aNumber
  349.     "Create a new instance of the receiver, with aNumber digits."
  350.  
  351.     ^self new noOfDigits: aNumber! !
  352.  
  353. !Calculator class methodsFor: 'class initialization'!
  354.  
  355. initialize
  356.     "Initialize default values."
  357.     "Calculator initialize."
  358.  
  359.     DefaultNoOfDigits _ 12! !
  360.  
  361. Calculator initialize!
  362.  
  363.  
  364. Controller subclass: #CalculatorKeypadController
  365.     instanceVariableNames: ''
  366.     classVariableNames: ''
  367.     poolDictionaries: ''
  368.     category: 'Interface-Calculator'!
  369.  
  370.  
  371. !CalculatorKeypadController methodsFor: 'control defaults'!
  372.  
  373. controlActivity
  374.     "Pass control to a subView corresponding to a pressed keyboard key or to a mouse
  375.     button pressed, if any."
  376.  
  377.     sensor keyboardPressed
  378.         ifTrue: [self processMenuKey]
  379.         ifFalse: [self controlToNextLevel]!
  380.  
  381. isControlActive
  382.     ^((sensor keyboardPressed) | (view containsPoint: sensor cursorPoint))
  383.         & ((sensor blueButtonPressed not) & (sensor yellowButtonPressed not))!
  384.  
  385. processMenuKey
  386.     "The user typed a key on the keyboard.  Give control to the subView that
  387.     is selected by this key."
  388.  
  389.     | aView |
  390.     aView _ view subViewContainingCharacter: sensor keyboard.
  391.     aView ~~ nil
  392.         ifTrue: [aView controller sendMessage]
  393.         ifFalse: [view superView flash]! !
  394.  
  395. View subclass: #CalculatorView
  396.     instanceVariableNames: 'sevenSegForms cachedFormSize '
  397.     classVariableNames: 'KeyForms '
  398.     poolDictionaries: ''
  399.     category: 'Interface-Calculator'!
  400.  
  401.  
  402. !CalculatorView methodsFor: 'initialize-release'!
  403.  
  404. initialize
  405.  
  406.     super initialize.
  407.     sevenSegForms _ Array new: 12.! !
  408.  
  409. !CalculatorView methodsFor: 'displaying'!
  410.  
  411. displayError
  412.     "Display the error indication - a letter E."
  413.  
  414.     ((sevenSegForms at: 12) notNil and: [cachedFormSize = self currentFormSize])
  415.             ifFalse: [self newCachedForms].
  416.     (sevenSegForms at: 12) displayAt: self digitDisplayOrigin!
  417.  
  418. displayLeftDigits: aCollection
  419.     "Display, in seven segment form, the digits in aCollection,
  420.      starting from the left."
  421.  
  422.     "The first field in the array is the right (least significant) digit."
  423.  
  424.     | origin width |
  425.     ((sevenSegForms at: 1) isNil or: [cachedFormSize ~= self currentFormSize])
  426.             ifTrue: [self newCachedForms].
  427.     width _ self digitBox width.
  428.     origin _ self digitDisplayOrigin.
  429.     1 to: aCollection size do: [ :count |
  430.         (sevenSegForms at: (aCollection at: count) + 1)
  431.             displayAt: origin + (count * width@0)]!
  432.  
  433. displayLeftPoint: aPosition
  434.     "Display a small black form representing the decimal point,
  435.      in a left justified manner."
  436.  
  437.     | origin height width size form |
  438.     width _ self digitBox width.
  439.     height _ self digitBox height.
  440.     size _ width // 8 max: 2.
  441.     origin _ self insetDisplayBox origin +
  442.         (width * aPosition@0) +
  443.         ((size negated // 2)@(self formBox height + self digitOffset y - size)).
  444.     form _ Form new extent: size@size.
  445.     form black.
  446.     form displayAt: origin!
  447.  
  448. displayMinus
  449.     "Display the minus sign."
  450.  
  451.     ((sevenSegForms at: 11) notNil
  452.         and: [cachedFormSize = self currentFormSize])
  453.             ifFalse: [self newCachedForms].
  454.     (sevenSegForms at: 11) displayAt: self digitDisplayOrigin!
  455.  
  456. displayRightDigits: aCollection 
  457.     "Display, in seven segment form, the digits in aCollection,  
  458.      starting from the right hand side."
  459.     "The first field in the array is the right (least significant) digit."
  460.  
  461.     | origin width noOfDigits |
  462.     width _ self digitBox width.
  463.     origin _ self digitDisplayOrigin.
  464.     ((sevenSegForms at: 1) isNil or: [cachedFormSize ~= self currentFormSize])
  465.             ifTrue: [self newCachedForms].
  466.     noOfDigits _ model noOfDigits + 1.
  467.     aCollection size to: 1 by: -1 do: [:count |
  468.         (sevenSegForms at: (aCollection at: aCollection size - count + 1) + 1)
  469.                 displayAt: origin + (noOfDigits - count * width @ 0)]!
  470.  
  471. displayRightPoint: aPosition
  472.     "Display a small black form representing the decimal point,
  473.      suitable for a right justified display."
  474.  
  475.     | origin height width size form position |
  476.     position _ model noOfDigits + 1 - aPosition.
  477.     width _ self digitBox width.
  478.     height _ self digitBox height.
  479.     size _ width // 8 max: 2.
  480.     origin _ self insetDisplayBox origin +
  481.         (width * position@0) +
  482.         ((size negated // 2)@(self formBox height + self digitOffset y - size)).
  483.     form _ Form new extent: size@size.
  484.     form black.
  485.     form displayAt: origin!
  486.  
  487. displayView
  488.     "Display the displayValue in seven-segment form."
  489.  
  490.     | digits value remainder count noOfDigits pointPosition trailingZeros |
  491.     model errorFlag ifTrue: [^self displayError].
  492.     value _ model displayValue.
  493.     value < 0 ifTrue: [
  494.         self displayMinus.
  495.         value _ value negated].
  496.     noOfDigits _ model noOfDigits.
  497.     digits _ OrderedCollection new: noOfDigits.
  498.     count _ 1.
  499.     remainder _ value - value truncated.
  500.     [value >= 10] whileTrue: [
  501.         digits addFirst: value \\ 10.
  502.         value _ value // 10.
  503.         count _ count + 1].
  504.     digits addFirst: value truncated.
  505.     count _ count + 1.
  506.     pointPosition _ count.
  507.     [(count <= noOfDigits) & (remainder ~= 0)] whileTrue: [
  508.         remainder _ remainder * 10.
  509.         value _ remainder truncated.
  510.         digits addLast: value.
  511.         remainder _ remainder - value.
  512.         count _ count + 1].
  513.     trailingZeros _ model trailingZeros.
  514.     [(count <= noOfDigits) & (trailingZeros > 0)] whileTrue: [
  515.         digits addLast: 0.
  516.         trailingZeros _ trailingZeros - 1.
  517.         count _ count + 1].
  518.     model leftJustify
  519.       ifTrue: [
  520.         self displayLeftDigits: digits.
  521.         self displayLeftPoint: pointPosition]
  522.       ifFalse: [
  523.         self displayRightDigits: digits.
  524.         self displayRightPoint: (count -  pointPosition)].!
  525.  
  526. update: aParameter
  527.  
  528.     self display! !
  529.  
  530. !CalculatorView methodsFor: 'private'!
  531.  
  532. currentFormSize
  533.     "Answer with the new current form size."
  534.  
  535.     ^self formBox extent!
  536.  
  537. digitBox
  538.     "Answers a rectangle which is the box used to divide up
  539.      the calculator digit display area."
  540.  
  541.     | box |
  542.     box _ self insetDisplayBox copy.
  543.     box width: (box width // (model noOfDigits +1)).
  544.     ^box!
  545.  
  546. digitDisplayOrigin
  547.     "Answer the origin for a digit display form for display."
  548.  
  549.     ^(self insetDisplayBox origin) + (self digitOffset)!
  550.  
  551. digitOffset
  552.     "Offset between digitBox and formBox."
  553.  
  554.     ^(self formBox origin) - (self digitBox origin)!
  555.  
  556. formBox
  557.     "Answers a rectangle which is the box used to display the
  558.      form representing calculator digits."
  559.  
  560.     | box |
  561.     box _ self digitBox.
  562.     ^box insetBy: (box width // 8 max: 3)@(box height // 8 max: 3)!
  563.  
  564. newCachedForms
  565.     "Re-calculates all the cached forms."
  566.  
  567.     | size form halfHeight lineWidth |
  568.     size _ self currentFormSize.
  569.     lineWidth _    ((size x / 8) max: 2) roundTo: 2.
  570.     halfHeight _ ((size y / 2) + (lineWidth / 2)).
  571.     0 to: 11 do: [:count |
  572.         form _ Form new extent: size.
  573.         "Bottom Left Segment."
  574.         (#(1 3 4 5 7 9 10) includes: count) ifFalse: [
  575.             form fill: (0@(size y - halfHeight + 1) extent: (lineWidth@halfHeight))
  576.                   rule: Form over
  577.                   mask: Form black].
  578.         "Bottom Right Segment."
  579.         (#(2 10 11) includes: count) ifFalse: [
  580.             form fill: ((size x - lineWidth)@(size y - halfHeight + 1) extent: (lineWidth@halfHeight))
  581.                   rule: Form over
  582.                   mask: Form black].
  583.         "Bottom Segment."
  584.         (#(1 4 7 10) includes: count) ifFalse: [
  585.             form fill: (0@(size y - lineWidth) extent: ((size x)@lineWidth))
  586.                   rule: Form over
  587.                   mask: Form black].
  588.         "Center Segment."
  589.         (#(0 1 7) includes: count) ifFalse: [
  590.             form fill: (0@(size y - halfHeight) extent: ((size x)@lineWidth))
  591.                   rule: Form over
  592.                   mask: Form black].
  593.         "Top Left Segment."
  594.         (#(1 2 3 7 10) includes: count) ifFalse: [
  595.             form fill: (0@0 extent: (lineWidth@halfHeight))
  596.                   rule: Form over
  597.                   mask: Form black].
  598.         "Top Right Segment."
  599.         (#(5 6 10 11) includes: count) ifFalse: [
  600.             form fill: ((size x - lineWidth)@0 extent: (lineWidth@halfHeight))
  601.                   rule: Form over
  602.                   mask: Form black].
  603.         "Top Segment."
  604.         (#(1 4 10) includes: count) ifFalse: [
  605.             form fill: (0@0 extent: ((size x)@lineWidth))
  606.                   rule: Form over
  607.                   mask: Form black].
  608.  
  609.         sevenSegForms at: count + 1 put: form
  610.     ].
  611.     cachedFormSize _ size! !
  612. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  613.  
  614. CalculatorView class
  615.     instanceVariableNames: ''!
  616.  
  617.  
  618. !CalculatorView class methodsFor: 'instance creation'!
  619.  
  620. open
  621.     "Create and schedule a new instance of the receiver on a new
  622.      Calculator."
  623.     "CalculatorView open."
  624.  
  625.     self openOn: Calculator new!
  626.  
  627. openOn: aCalculator
  628.     "Create and schedule a new instance of the receiver on aCalculator."
  629.     "CalculatorView openOn: Calculator new."
  630.  
  631.     | topView view |
  632.     topView _ StandardSystemView new.
  633.     topView label: 'Calculator'.
  634.     topView borderWidth: 2.
  635.     topView insideColor: Form lightGray.
  636.     topView minimumSize: 220@160.
  637.  
  638.     view _ View new model: aCalculator controller: CalculatorController new.
  639.     topView addSubView: view.
  640.     self createSubViewsIn: view.
  641.  
  642.     topView controller open! !
  643.  
  644. !CalculatorView class methodsFor: 'class initialization'!
  645.  
  646. initialize
  647.     "CalculatorView initialize."
  648.  
  649.     | text form |
  650.     KeyForms _ Array new: 20.
  651.     0 to: 9 do: [ :number |
  652.         form _ Form new extent: 10@14.
  653.         text _ (number printString asText emphasizeFrom: 1 to: 1 with: 11)
  654.             asParagraph asForm.
  655.         form copy: (text boundingBox) from: 0@0 in: text rule: Form over.
  656.         KeyForms at: (number + 1) put: form].
  657.  
  658.     form _ Form new extent: 10@14.
  659.     (Form dotOfSize: 8) displayOn: form at: 5@7.
  660.     KeyForms at: 11 put: form.
  661.  
  662.     form _ Form new extent: 10@14.
  663.     text _ ('=' asText emphasizeFrom: 1 to: 1 with: 11)
  664.             asParagraph asForm.
  665.     form copy: (text boundingBox) from: 0@0 in: text rule: Form over.
  666.     KeyForms at: 12 put: form.
  667.  
  668.     form _ Form new extent: 10@14.
  669.     text _ ('+' asText emphasizeFrom: 1 to: 1 with: 11)
  670.             asParagraph asForm.
  671.     form copy: (text boundingBox) from: 0@0 in: text rule: Form over.
  672.     KeyForms at: 13 put: form.
  673.  
  674.     form _ Form new extent: 10@14.
  675.     text _ ('-' asText emphasizeFrom: 1 to: 1 with: 11)
  676.             asParagraph asForm.
  677.     form copy: (text boundingBox) from: 0@0 in: text rule: Form over.
  678.     KeyForms at: 14 put: form.
  679.  
  680.     form _ Form new extent: 10@14.
  681.     text _ ('X' asText emphasizeFrom: 1 to: 1 with: 11)
  682.             asParagraph asForm.
  683.     form copy: (text boundingBox) from: -1@0 in: text rule: Form over.
  684.     KeyForms at: 15 put: form.
  685.  
  686.     form _ Form new extent: 10@14.
  687.     text _ ('/' asText emphasizeFrom: 1 to: 1 with: 11)
  688.             asParagraph asForm.
  689.     form copy: (text boundingBox) from: 0@0 in: text rule: Form over.
  690.     KeyForms at: 16 put: form.
  691.  
  692.     form _ Form extent: 10@14 fromArray:
  693.         #(12288 12288 64512 64704
  694.            12672 13056 1536 3072
  695.             6144 12288 26560 51136 0 0) offset: 0@0.
  696.     KeyForms at: 17 put: form.
  697.  
  698.     form _ Form extent: 10@14 fromArray:
  699.         # (0 1088 1088 640 256 256 512 35328
  700.             34816 20480 8192 20480 34816 34816 ) offset: 0@0.
  701.     KeyForms at: 18 put: form.
  702.  
  703.     form _ Form new extent: 10@14.
  704.     text _ ('.' asText emphasizeFrom: 1 to: 1 with: 11)
  705.             asParagraph asForm.
  706.     form copy: (text boundingBox) from: -2@0 in: text rule: Form over.
  707.     KeyForms at: 19 put: form.
  708.  
  709.     form _ Form new extent: 10@14.
  710.     text _ ('C' asText emphasizeFrom: 1 to: 1 with: 11)
  711.             asParagraph asForm.
  712.     form copy: (text boundingBox) from: -1@0 in: text rule: Form over.
  713.     KeyForms at: 20 put: form.! !
  714.  
  715. !CalculatorView class methodsFor: 'class access'!
  716.  
  717. keyForms
  718.     "Answer with an array of forms used to display the keys."
  719.     "CalculatorView keyForms do: [ :each |
  720.         each displayAt: 100@100.
  721.         (Delay forSeconds: 1) wait]."
  722.  
  723.     ^KeyForms! !
  724.  
  725. !CalculatorView class methodsFor: 'private'!
  726.  
  727. addButtonViewsIn: aView
  728.     "Adds all the button subViews, for the calculator."
  729.  
  730.     | offsets labels actions chars aButton aSwitchView |
  731.     offsets _ OrderedCollection new: 20.
  732.     #(15 45 75 105 135) do: [:i | offsets addLast: i@44].
  733.     #(15 45 75 105 135) do: [:i | offsets addLast: i@74].
  734.     #(15 45 75 105 135) do: [:i | offsets addLast: i@104].
  735.     #(15 45 75 105 135) do: [:i | offsets addLast: i@134].
  736.  
  737.     labels _ OrderedCollection new: 20.
  738.     #(8 9 10 20 11) do: [:i | labels addLast: (KeyForms at: i)].
  739.     #(5 6 7 13 14) do: [:i | labels addLast: (KeyForms at: i)].
  740.     #(2 3 4 15 16) do: [:i | labels addLast: (KeyForms at: i)].
  741.     #(1 19 18 17 12) do: [:i | labels addLast: (KeyForms at: i)].
  742.  
  743.     actions _ #(#add7 #add8 #add9 #clearEntry #clear
  744.                  #add4 #add5 #add6 #add #subtract
  745.                  #add1 #add2 #add3 #multiply #divide
  746.                  #add0 #point #raiseTo #changeSign #equals).
  747.  
  748.     chars _ #($7 $8 $9 $e $c
  749.                 $4 $5 $6 $+ $-
  750.                 $1 $2 $3 $* $/
  751.                 $0 $. $^ $s $=).
  752.  
  753.     1 to: 20 do: [ :i |
  754.         aButton _ Button newOff.
  755.         aButton onAction: [aView model perform: (actions at: i)].
  756.         aSwitchView _ SwitchView new model: aButton.
  757.         aSwitchView key: (chars at: i).
  758.         aSwitchView borderWidth: 2.
  759.         aSwitchView insideColor: Form white.
  760.         aSwitchView label: (labels at: i).
  761.         aSwitchView translateBy: (offsets at: i).
  762.         aSwitchView controller: IndicatorOnSwitchController new.
  763.         aView addSubView: aSwitchView.
  764.     ].!
  765.  
  766. createSubViewsIn: aView
  767.     "Build subviews in aView."
  768.  
  769.     | buttonView displayView |
  770.     aView window: (0@0 extent: 160@160).
  771.  
  772.     displayView _ self new model: aView model controller: NoController new.
  773.     displayView borderWidth: 2.
  774.     displayView insideColor: Form white.
  775.     aView
  776.         addSubView: displayView
  777.         window: aView window
  778.         viewport: (2@2 corner: 158@32).
  779.  
  780.     buttonView _ CalculatorKeypadView new
  781.         model: aView model
  782.         controller: CalculatorKeypadController new.
  783.     buttonView borderWidth: 2.
  784.     buttonView insideColor: Form gray.
  785.     aView
  786.         addSubView: buttonView
  787.         window: (2@34 corner: 158@158)
  788.         viewport: (2@34 corner: 158@158).
  789.     self addButtonViewsIn: buttonView.! !
  790.  
  791. CalculatorView initialize!
  792.  
  793.  
  794. View subclass: #CalculatorKeypadView
  795.     instanceVariableNames: ''
  796.     classVariableNames: ''
  797.     poolDictionaries: ''
  798.     category: 'Interface-Calculator'!
  799.  
  800.  
  801. !CalculatorKeypadView methodsFor: 'subView access'!
  802.  
  803. subViewContainingCharacter: aCharacter
  804.     "Answer the receiver's subView that corresponds to the key, aCharacter.
  805.     Answer nil if no subView is selected by aCharacter."
  806.  
  807.     self subViews reverseDo: 
  808.         [:aSubView |
  809.         (aSubView containsKey: aCharacter asLowercase) ifTrue: [^aSubView]].
  810.     ^nil! !
  811.